#include <semaphore.h>
#include "https_service.h"
#include "HttpsServer.h"
#include "stpool.h"
#include "msglog.h"

sem_t semSessionPoolIdle;
struct __client_session* get_avail_session(struct __client_session* session_pool, int listSz)
{
	int i;
	sem_wait(&semSessionPoolIdle);
	for(i = 0; i < listSz; i++)
	{
		if(session_pool[i].req_status == HTTPS_REQ_CPLT ||
		   session_pool[i].req_status == HTTPS_REQ_DUMMY )
		{
			session_pool[i].req_status = HTTPS_REQ_DOING;
			session_pool[i].idx = i;
			fprintf(stderr, "[DEBUG]: Get session block[%d] from Pool.\n", i);
			sem_post(&semSessionPoolIdle);
			return &session_pool[i];
		}
	}
	sem_post(&semSessionPoolIdle);
	return NULL;
}

void release_session(struct __client_session* session)
{
	sem_wait(&semSessionPoolIdle);	
	session->req_status = HTTPS_REQ_CPLT;
	session->fd = -1;
	fprintf(stderr, "[DEBUG]: Release session block[%d] to Pool.\n", session->idx);
	sem_post(&semSessionPoolIdle);	
}

/**
  * @brief  事务处理程序.
  * @Notes  stpool线程池模型下的事务处理程序固定格式.
  * @param  ptsk, stpool线程传入参数
  * @retval None.
  */
void HTTPS_TASK(struct sttask *ptsk)
{
	struct __client_session* session = (struct __client_session*)(ptsk->task_arg);

	DealWithClient(session);

	release_session(session);
}


void* thrfx_https_service(void* para)
{
	char * str ;
	SERVER_PORT = 443 ;
	DEBUG_MODE = 0 ;
	sprintf( DOCUMENT_ROOT ,  "%s" , "../www/" ) ;
	sprintf( LOG_FILE_PATH ,  "%s" , "./HttpsServer.log" ) ;
	sprintf( CERT_FILE_PATH , "%s" , "../rsa/cert.pem" ) ;
	sprintf( KEY_FILE_PATH ,  "%s" , "../rsa/key.pem" ) ;

	if ( isFileExist("../HttpsServer.conf") == 1 )
	{
		ReadConfFile("../HttpsServer.conf") ;
	}
	
	ShowCfg() ;

	str = QueryValue( "SERVER" , "SERVER_PORT" ) ;
	if(str != NULL ) SERVER_PORT = atoi(str) ;
	str = QueryValue( "SERVER" , "DOCUMENT_ROOT" ) ;
	if(str != NULL ) strcpy(DOCUMENT_ROOT , str);
	str = QueryValue( "SERVER" , "LOG_FILE_PATH" ) ;
	if(str != NULL ) strcpy(LOG_FILE_PATH , str);
	str = QueryValue( "SERVER" , "DEBUG_MODE" ) ;
	if(str != NULL ) DEBUG_MODE = atoi( str );
	str = QueryValue( "SERVER" , "CERT_FILE_PATH" ) ;
	if(str != NULL ) strcpy(CERT_FILE_PATH , str);
	str = QueryValue( "SERVER" , "KEY_FILE_PATH" ) ;
	if(str != NULL ) strcpy(KEY_FILE_PATH , str);


	char logstring[1024];
	int sockfd , clientfd ;
	struct sockaddr_in addr ;
	int addr_len = sizeof( struct sockaddr_in );
	pthread_t clientThread;
	

	printf("INFO: To start server by (SERVER_PORT:%d ; DOCUMENT_ROOT:%s)!\n",SERVER_PORT , DOCUMENT_ROOT );
	
	SSL_library_init();
	ctx = InitServerCTX();/* initialize SSL */
	LoadCertificates(ctx, CERT_FILE_PATH, KEY_FILE_PATH);  /* load certs */
	
	if( ( sockfd = socket(AF_INET , SOCK_STREAM , 0) ) < 0 )
	{
		perror("socket");
		return (void*)1;
	}
	bzero(&addr , sizeof(addr));
	addr.sin_family = AF_INET ;
	addr.sin_port = htons(SERVER_PORT) ;
	addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
	if( bind(sockfd , (struct sockaddr *)&addr , sizeof(addr)) < 0 )
	{
		perror("connet");
		return (void*)2;
	}
	if( listen(sockfd , 5) < 0 )
	{
		perror("listen");
		return (void*)3;
	}
	sprintf(logstring,"MAINTHREAD : The server is already (SERVER_PORT:%d ; DOCUMENT_ROOT:%s)!\n",SERVER_PORT , DOCUMENT_ROOT );
	writelogstring(logstring);

	/* 为工作负载分配 传入参数 存储空间 */
	struct __client_session* _session_pool = (struct __client_session*)malloc
								(MAX_HTTPS_REQ * sizeof(struct __client_session));
	int i;
	for(i = 0; i < MAX_HTTPS_REQ; i++)
	{
		_session_pool[i].fd = -1;
		_session_pool[i].req_status = HTTPS_REQ_DUMMY;
	}

	/* pshared=0, 其他进程不共享该信号量
	   初始值:1, 该信号量可用 */
	sem_init(&semSessionPoolIdle,  0, 1);

	/* 线程池初始化 */
	stpool_t *thrpool;
	long eCAPs;

	// 设置stpool库的报错级别为: LOG_ERR，只显示严重错误 
    MSG_log_set_level(LOG_ERR);
    eCAPs = eCAP_F_DYNAMIC|eCAP_F_SUSPEND|eCAP_F_THROTTLE|eCAP_F_ROUTINE|
			eCAP_F_DISABLEQ|eCAP_F_PRIORITY|eCAP_F_WAIT_ALL;
	
	/* 初始化线程池 */
	thrpool = stpool_create("HTTPS-SERVICE", eCAPs, 100, 60, 0, 1);
	if(!thrpool)
	{ 
		fprintf(stderr, "ThreadPool/> {ERROR} Application-Workers thread pool initialize failed!\n");
	}
	else{ 
		fprintf(stderr, "%s\n", stpool_stat_print(thrpool));
	}


	while(1)
	{
		clientfd = accept(sockfd ,(struct sockaddr *) &addr , (socklen_t *)&addr_len) ;
		//printf("INFO: Connect with %s:%d ! \n" ,inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)) ;
		if( clientfd < 0 )
		{
			perror("accept");
			continue ;
		}
		
		/*
		if (pthread_create(&clientThread , NULL, (void *)DealWithClient, &clientfd) != 0)
			perror("pthread_create");
		*/

		/* 传入线程参数 */
		struct __client_session* _session = get_avail_session(_session_pool, MAX_HTTPS_REQ);
		_session->fd = clientfd;
		strcpy(_session->ip, inet_ntoa(addr.sin_addr));
		_session->port = ntohs(addr.sin_port);
		
		// 事务处理线程所用到的变量，通过函数的第5个参数传入
		stpool_add_routine(thrpool, "http-service", HTTPS_TASK, NULL, _session, NULL); 
			
	}
	close(sockfd) ;
	SSL_CTX_free(ctx);
	
	/* 释放线程池资源 */
	if(thrpool != NULL)
	{
		stpool_release(thrpool);
		fprintf(stderr, "ThreadPool/> {INFO} https thread-pool release.\n");
	}else
	{
		fprintf(stderr, "ThreadPool/> {INFO} https thread-pool is null.\n");
	}

	/* 释放工作负载 传入参数 存储空间 */
	free(_session_pool);
}